/* 
 * USB CID Driver - 1.0
 *
 * Copyright (C) 2006 Hansung Chun (adol17@dreamwiz.com)
 *
 *     This file is part of USB CID Driver.
 * 
 *     USB CID Driver is free software; you can redistribute it and/or
 *     modify it under the terms of the GNU General Public License as
 *     published by the Free Software Foundation, version 2.
 *
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

#include <linux/usb.h>

#include "usbcid_fw.h"

#define DRIVER_AUTHOR "Hansung Chun, adol17@dreamwiz.com"
#define DRIVER_DESC "USB CID Loader Driver"

#define VENDOR_ID 0x0547
#define PRODUCT_ID 0x2235

static struct usb_device_id id_table [] = {
	{ USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
	{},
};
MODULE_DEVICE_TABLE (usb, id_table);

struct usb_cid {
	struct usb_device *udev;
	struct usb_interface *interface;
};

static int cidloader_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
	int retval = 0;
	__u8 cpucs_reg = 0;
	unsigned char *buffer = NULL;	
	struct usb_cid *dev = NULL;
	const struct ezusb_hex_record *record = &usbcid_firmware[0];
	
	buffer = kmalloc( sizeof(record->data), GFP_KERNEL );
	if(buffer == NULL) {
		err("USBCID: Out of memory");
		goto error;
	}
	
	dev = kmalloc( sizeof(struct usb_cid), GFP_KERNEL );
	if(dev == NULL) {
		err("USBCID: Out of memory");
		goto error;
	}
	
	dev->udev = usb_get_dev( interface_to_usbdev(interface) );

	//Load Firmware	
	cpucs_reg = 0x01;
	memcpy( buffer, &cpucs_reg, 1 );
	retval = usb_control_msg( dev->udev, usb_sndctrlpipe(dev->udev, 0), 
			0xA0, 0x40, 0x7F92, 0, buffer, 1, HZ*10 );
	if(!retval) {
		printk("USBCID: Error - usb_control_msg()");
		goto error;
	}
	
	while( record->address != 0xffff ) {
		memcpy( buffer, record->data, record->data_size );	
		retval = usb_control_msg( dev->udev, usb_sndctrlpipe( dev->udev, 0 ), 
				0xA0, 0x40, record->address, 0, buffer, record->data_size, HZ*10 );
		if(!retval) {
			printk("USBCID: Error - usb_control_msg()");
			goto error;
		}
		record++;
	}
	
	cpucs_reg = 0x00;
	memcpy( buffer, &cpucs_reg, 1 );
	retval = usb_control_msg( dev->udev, usb_sndctrlpipe(dev->udev, 0), 
			0xA0, 0x40, 0x7F92, 0, buffer, 1, HZ*10 );
	if(!retval) {
		printk("USBCID: Error - usb_control_msg()");
		goto error;
	}
	
	printk("USBCID: Success - cidloader_probe()\n");
	kfree(buffer);
	kfree(dev);
	return 0;
error:
	kfree(buffer);
	kfree(dev);
	return retval;
}

static void cidloader_disconnect(struct usb_interface* interface)
{	
	lock_kernel();	
	printk("USBCID: Success - cidloader_disconnect()\n");	
	unlock_kernel();	
}

static struct usb_driver cidloader_driver = {
	.name =		"cidloader",
	.probe =	cidloader_probe,
	.disconnect =	cidloader_disconnect,
	.id_table =	id_table,
};

static int __init usb_cidloader_init(void) 
{
	int retval=0;

	retval=usb_register(&cidloader_driver);
	if(retval) {
		err("USBCID: usb_register failed. Error number %d", retval);
	}

	return retval;
}

static void __exit usb_cidloader_exit(void) 
{
	usb_deregister(&cidloader_driver);
}

module_init(usb_cidloader_init);
module_exit(usb_cidloader_exit);

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");

